package gobase

import (
	"sync/atomic"
)

// 实例对象

import (
	"fmt"
	"io"
	"runtime"
	"sync"
)

var (
	instanceAliveN int32 = 0
)

func GetInstanceAliveN() int32 {
	return atomic.LoadInt32(&instanceAliveN)
}

type instanceType interface{}

type syncInstanceOption[T instanceType] struct {
	createFunc func(s string) (rval interface{}, err error)
	initFunc   func(obj interface{}) T
	finalFunc  func(ins T)
	validFunc  func(ins T) bool
}

type SyncInstance[T instanceType] struct {
	option   syncInstanceOption[T]
	lk       sync.RWMutex
	obj      interface{} // 创建的对象
	instance T           // 对象转换后的操作实例
	conf     string      // urlencode
}

type syncInstanceOptionFunc[T instanceType] func(opt *syncInstanceOption[T])

func NilValue[T instanceType]() T {
	var nilV T
	return nilV
}

func DefaultCreateInstanceObjectFunc(s string) (rval interface{}, err error) {
	confMap := NewStrMap()
	confMap.URLFormDecode(s)
	cls := confMap["class"]
	// 直接获取内置的操作对象
	cid := fmt.Sprintf("instance.%s", cls)
	return CreateFactoryInstance(cid, confMap)
}

// 传入的参数创建对象, args[0].(string)
func WithCreateFunc[T instanceType](fn func(s string) (rval interface{}, err error)) syncInstanceOptionFunc[T] {
	return func(o *syncInstanceOption[T]) {
		o.createFunc = fn
	}
}

func WithInitFunc[T instanceType](fn func(obj interface{}) T) syncInstanceOptionFunc[T] {
	return func(o *syncInstanceOption[T]) {
		o.initFunc = fn
	}
}

func WithValidFunc[T instanceType](fn func(ins T) bool) syncInstanceOptionFunc[T] {
	return func(o *syncInstanceOption[T]) {
		o.validFunc = fn
	}
}

func WithFinalFunc[T instanceType](fn func(ins T)) syncInstanceOptionFunc[T] {
	return func(o *syncInstanceOption[T]) {
		o.finalFunc = fn
	}
}

func newInstance[T instanceType]() *SyncInstance[T] {
	rval := &SyncInstance[T]{}
	rval.option.createFunc = DefaultCreateInstanceObjectFunc
	atomic.AddInt32(&instanceAliveN, 1)
	runtime.SetFinalizer(rval, func(obj interface{}) {
		atomic.AddInt32(&instanceAliveN, -1)
	})
	return rval
}

func NewSyncInstance[T instanceType](opts ...syncInstanceOptionFunc[T]) *SyncInstance[T] {
	rval := newInstance[T]()
	for _, opt := range opts {
		opt(&rval.option)
	}
	return rval
}

func (this *SyncInstance[T]) closeInner() {
	if this.obj != nil {
		if this.option.finalFunc != nil {
			this.option.finalFunc(this.instance)
		}

		if ref, ok := this.obj.(*ObjectInnerRef); ok {
			ref.ReleaseRef()
		} else if c, ok := this.obj.(io.Closer); ok {
			c.Close()
		}
		this.obj = nil
	}

}

func (this *SyncInstance[T]) Close() {
	this.lk.Lock()
	defer this.lk.Unlock()
	this.closeInner()
}

func (this *SyncInstance[T]) valid() bool {
	if this.option.validFunc != nil {
		return this.option.validFunc(this.instance)
	}
	return this.obj != nil
}

// true: 表示有效
func (this *SyncInstance[T]) Valid() bool {
	this.lk.RLock()
	defer this.lk.RUnlock()
	return this.valid()
}

func (this *SyncInstance[T]) GetConf() string {
	if this.lk.TryRLock() {
		defer this.lk.RUnlock()
		return this.conf
	}
	return "ERR:Dead Lock"
}

func (this *SyncInstance[T]) Object() interface{} {
	this.lk.RLock()
	defer this.lk.RUnlock()
	return this.obj
}

// 需要传入转换函数否则无法执行
func (this *SyncInstance[T]) Exec(fn func(ins T)) {
	this.lk.RLock()
	defer this.lk.RUnlock()
	if !this.valid() {
		return
	}
	fn(this.instance)
	return
}

func (this *SyncInstance[T]) ExecObj(fn func(obj interface{})) bool {
	this.lk.RLock()
	defer this.lk.RUnlock()
	if !this.valid() {
		return false
	}
	fn(this.obj)
	return true
}

func (this *SyncInstance[T]) UpdateConf(s string) (changed bool, err error) {
	this.lk.Lock()
	defer this.lk.Unlock()
	if s != this.conf || this.obj == nil {
		this.closeInner()
		this.conf = s
		changed = true
		if len(s) > 0 {
			rval, err := this.option.createFunc(s)
			if err == nil {
				this.obj = rval
				if this.option.initFunc != nil {
					this.instance = this.option.initFunc(this.obj)
				} else {
					this.instance, _ = rval.(T)
				}
			} else {
				return changed, err
			}
		}
		return
	} else {
		changed = false
		return
	}
}

func (this *SyncInstance[T]) ExecWithBool(fn func(ins T) bool) bool {
	this.lk.RLock()
	defer this.lk.RUnlock()
	if !this.valid() {
		return false
	}
	return fn(this.instance)
}

func (this *SyncInstance[T]) ExecWithError(fn func(ins T) error) error {
	this.lk.RLock()
	defer this.lk.RUnlock()
	if !this.valid() {
		return ErrInvalidObject
	}
	return fn(this.instance)
}

func (this *SyncInstance[T]) ExecWithStrErr(fn func(ins T) (string, error)) (string, error) {
	this.lk.RLock()
	defer this.lk.RUnlock()
	if !this.valid() {
		return "", ErrInvalidObject
	}
	return fn(this.instance)
}

func (this *SyncInstance[T]) ExecWithBufErr(fn func(ins T) ([]byte, error)) ([]byte, error) {
	this.lk.RLock()
	defer this.lk.RUnlock()
	if !this.valid() {
		return nil, ErrInvalidObject
	}
	return fn(this.instance)
}

func (this *SyncInstance[T]) ExecWithI64Err(fn func(ins T) (int64, error)) (int64, error) {
	this.lk.RLock()
	defer this.lk.RUnlock()
	if !this.valid() {
		return 0, ErrInvalidObject
	}
	return fn(this.instance)
}

func (this *SyncInstance[T]) ExecWithI64Bool(fn func(ins T) (int64, bool)) (int64, bool) {
	this.lk.RLock()
	defer this.lk.RUnlock()
	if !this.valid() {
		return 0, false
	}
	return fn(this.instance)
}

func (this *SyncInstance[T]) ExecWithI64(fn func(ins T) int64) int64 {
	this.lk.RLock()
	defer this.lk.RUnlock()
	if !this.valid() {
		return 0
	}
	return fn(this.instance)
}
